package com.example.estemplate.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.Node;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.Objects;

/**
 * Elasticsearch客户端配置类
 * 负责创建和管理与Elasticsearch集群的连接
 */
@Configuration
@Slf4j
public class ElasticsearchConfig {

    /**
     * Elasticsearch集群节点地址列表
     * 格式为["host1:port1", "host2:port2"]
     */
    @Value("${elasticsearch.hosts}")
    private String[] hosts;

    /**
     * Elasticsearch认证用户名
     */
    @Value("${elasticsearch.username}")
    private String username;

    /**
     * Elasticsearch认证密码
     */
    @Value("${elasticsearch.password}")
    private String password;

    /**
     * 连接超时时间（毫秒）
     */
    @Value("${elasticsearch.connection-timeout}")
    private int connectionTimeout;

    /**
     * 套接字超时时间（毫秒）
     */
    @Value("${elasticsearch.socket-timeout}")
    private int socketTimeout;

    /*
     * 关于 RestHighLevelClient 被idea标黄的问题：
     * elasticsearch 7.x版本的客户端（RestHighLevelClient）已标记为弃用（但功能完整），
     * Elasticsearch Java Client 8.x 官方要求最低 Java 11，强行在 Java 8 运行时可能存在隐蔽问题（如部分 API 依赖新 JDK 特性）。
     * Spring Boot 2.7 默认集成的是 Elasticsearch 7.x 客户端，混用新旧客户端会导致依赖冲突。
     */
    /**
     * 创建并配置Elasticsearch高级REST客户端
     *
     * @return 配置好的RestHighLevelClient实例
     * @throws IllegalStateException 如果客户端创建失败
     */
    @Bean(destroyMethod = "close")
    public RestHighLevelClient restHighLevelClient() {
        try {
            // 创建基础RestClient构建器
            RestClientBuilder builder = RestClient.builder(createHttpHosts());

            // 配置请求超时参数
            builder.setRequestConfigCallback(requestConfigBuilder -> {
                // 设置连接超时时间
                requestConfigBuilder.setConnectTimeout(connectionTimeout);
                // 设置套接字超时时间
                requestConfigBuilder.setSocketTimeout(socketTimeout);
                return requestConfigBuilder;
            });

            // 如果配置了用户名和密码，设置认证信息
            if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
                // 创建凭证提供者
                final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
                // 设置全局范围的凭证
                credentialsProvider.setCredentials(AuthScope.ANY,
                        new UsernamePasswordCredentials(username, password));
                // 配置HTTP客户端认证
                builder.setHttpClientConfigCallback(httpClientBuilder -> {
                    httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                    return httpClientBuilder;
                });
            }

            // 配置节点故障监听器（可选）
            builder.setFailureListener(new RestClient.FailureListener() {
                @Override
                public void onFailure(Node node) {
                    // 记录节点故障日志
                    log.warn("Elasticsearch node {} failed", node.getHost());
                }
            });

            // 构建并返回高级客户端
            return new RestHighLevelClient(builder);
        } catch (Exception e) {
            //异常（如网络不可达、认证失败）， 捕获所有异常并转换为运行时异常
            throw new IllegalStateException("Failed to create Elasticsearch client", e);
        }
    }

    /**
     * 创建HttpHost数组
     *
     * @return 转换后的HttpHost数组
     */
    private HttpHost[] createHttpHosts() {
        // 将配置的host字符串数组转换为HttpHost对象数组
        return Arrays.stream(hosts)
                // 将每个host字符串转换为HttpHost对象
                .map(this::createHttpHost)
                // 过滤掉转换失败的对象
                .filter(Objects::nonNull)
                // 收集为数组
                .toArray(HttpHost[]::new);
    }

    /**
     * 将host字符串转换为HttpHost对象
     *
     * @param host 主机字符串，格式为"host:port"
     * @return 对应的HttpHost对象
     * @throws IllegalArgumentException 如果host格式无效
     */
    private HttpHost createHttpHost(String host) {
        try {
            // 拆分主机和端口
            String[] hostParts = host.split(":");
            // 阿里云ES必须使用HTTPS协议（非HTTP）
            // 创建并返回HttpHost对象
            return new HttpHost(hostParts[0], Integer.parseInt(hostParts[1]), "https");
            //return new HttpHost(hostParts[0], Integer.parseInt(hostParts[1]), "http");
        } catch (Exception e) {
            // 转换失败时抛出异常
            throw new IllegalArgumentException("Invalid Elasticsearch host: " + host, e);
        }
    }
}